<script>
import events from './events'

export default {
    name: 'MultiTab',
    data() {
        return {
            pathMapTo: {}, // 存储目的path，键为来源path,值为目的path
            pathMap: {}, // 存储来源path,值为来源path
            fullPathList: [],
            pages: [],
            activeKey: '',
            newTabIndex: 0
        }
    },
    created() {
        events.$off('open').$off('close').$off('rename')
        // bind event
        events
            .$on('open', (val) => {
                if (!val) {
                    throw new Error(`multi-tab: open tab ${val} err`)
                }
                this.activeKey = val
            })
            .$on('close', (val) => {
                if (!val) {
                    this.closeThat(this.$route.fullPath)
                    return
                }
                this.closeThat(val)
            })
            .$on('rename', ({ key, name }) => {
                try {
                    const item = this.pages.find((item) => item.fullPath === key)
                    item.meta.title = name
                    this.$forceUpdate()
                } catch (e) {
                }
            })

        // 对缓存值进行取值、判断、赋值
        const tabPathMap = sessionStorage.getItem('tabPathMap')
        const tabPathMapTo = sessionStorage.getItem('tabPathMapTo')
        const tabFullPathList = sessionStorage.getItem('tabFullPathList')
        const tabPages = sessionStorage.getItem('tabPages')
        if (tabFullPathList) {
            this.fullPathList = JSON.parse(tabFullPathList)
        } else {
            this.fullPathList.push(this.$route.fullPath)
        }
        if (tabPages) {
            this.pages = JSON.parse(tabPages)
        } else {
            this.pages.push(this.$route)
        }
        if (tabPathMap) {
            this.pathMap = JSON.parse(tabPathMap)
        }
        if (tabPathMapTo) {
            this.pathMapTo = JSON.parse(tabPathMapTo)
        }
        this.activeKey = this.$route.fullPath
    },
    methods: {
        // 解析目的path
        resolvePathMapTo(key) {
            this.currentKey = this.pathMapTo[key] || key
        },
        onEdit(targetKey, action) {
            this[action](targetKey, { sortRemove: true })
        },
        remove(targetKey, options = {}) {
            if (targetKey === '/index') return // 首页不可删除
            const realKey = this.pathMapTo[targetKey] || targetKey // 获取映射之后的真实路径值
            const flag = this.$multiTab.invokeCallback(realKey) // 调用tab关闭的回调
            if (flag) return // 如果调用成功，则不执行后续操作
            this.pages = this.pages.filter((page) => page.fullPath !== targetKey)
            this.fullPathList = this.fullPathList.filter((path) => path !== targetKey)
            for (const key in this.pathMapTo) {
                if (this.pathMapTo.hasOwnProperty(key) && targetKey === key) {
                    this.pathMapTo = Object.assign({}, this.pathMapTo, { [key]: '' }) // 删除tab时，将其目的map也清空,避免再次进入时，指向了目的path
                }
            }
            if (options.sortRemove) { // 是否顺序删除tab，为true时，每次都选中最后一个tab
                this.currentKey = this.fullPathList.length ? this.fullPathList[this.fullPathList.length - 1] : '/index'
            } else {
                // 判断当前标签是否关闭，若关闭则跳转到合适的标签页
                if (!this.fullPathList.includes(this.$route.fullPath)) {
                    this.selectPath(targetKey, options)
                }
            }
        },
        selectPath(key, options = {}) {
            // 判断是否存在源path
            const resolveKey =
                this.pathMap[key] && this.fullPathList.includes(this.pathMap[key])
                    ? this.pathMap[key]
                    : this.fullPathList[this.fullPathList.length - 1]
            if (options.clearPathMapTo) {
                this.pathMapTo = Object.assign({}, this.pathMapTo, { [resolveKey]: '' })
            }
            this.resolvePathMapTo(resolveKey)
            this.pathMap = Object.assign({}, this.pathMap, { [resolveKey]: '' })
        },

        // content menu
        closeThat(e) {
            // 判断是否为最后一个标签页，如果是最后一个，则无法被关闭
            if (this.fullPathList.length > 1) {
                this.remove(e, {
                    clearPathMapTo: true // 是否清除目的path
                })
            } else {
                this.$message.info('这是最后一个标签了, 无法被关闭')
            }
        },
        closeLeft(e) {
            const currentIndex = this.fullPathList.indexOf(e)
            if (currentIndex > 0) {
                this.fullPathList.forEach((item, index) => {
                    if (index < currentIndex) {
                        this.remove(item)
                    }
                })
            } else {
                this.$message.info('左侧没有标签')
            }
        },
        closeRight(e) {
            const currentIndex = this.fullPathList.indexOf(e)
            if (currentIndex < this.fullPathList.length - 1) {
                this.fullPathList.forEach((item, index) => {
                    if (index > currentIndex) {
                        this.remove(item)
                    }
                })
            } else {
                this.$message.info('右侧没有标签')
            }
        },
        closeAll(e) {
            const currentIndex = this.fullPathList.indexOf(e)
            this.fullPathList.forEach((item, index) => {
                if (index !== currentIndex) {
                    this.remove(item)
                }
            })
        },
        closeMenuClick(key, route) {
            this[key](route)
        },
        renderTabPaneMenu(e) {
            return (
                <a-menu
                    {...{
                        on: {
                            click: ({ key, item, domEvent }) => {
                                this.closeMenuClick(key, e)
                            }
                        }
                    }}
                >
                    <a-menu-item key="closeThat">关闭当前标签</a-menu-item>
                    <a-menu-item key="closeRight">关闭右侧</a-menu-item>
                    <a-menu-item key="closeLeft">关闭左侧</a-menu-item>
                    <a-menu-item key="closeAll">关闭其它</a-menu-item>
                </a-menu>
            )
        },
        // render
        renderTabPane(title, keyPath) {
            const menu = this.renderTabPaneMenu(keyPath)

            return (
                <a-dropdown overlay={menu} trigger={['contextmenu']}>
                    <span style={{ userSelect: 'none' }}>{title}</span>
                </a-dropdown>
            )
        }
    },
    watch: {
        $route: function(newVal, oldVal) {
            const { noTab } = newVal.meta
            const newKey = newVal.fullPath
            const oldKey = oldVal.fullPath
            this.currentKey = newKey
            if (this.fullPathList.indexOf(newVal.fullPath) < 0) {
                if (!this.pathMap[newKey]) {
                    this.pathMap = Object.assign({}, this.pathMap, { [newKey]: oldKey }) // 存储路径来源关系
                }
                if (!noTab) {
                    // 不加入tab列表
                    this.fullPathList.push(newVal.fullPath)
                    this.pages.push(newVal)
                } else {
                    if (this.pathMap[newKey] === oldKey) { // 当前路由fullPath值的源path和上一个路由的fullPath相等时，则存储其目的path
                        this.pathMapTo = Object.assign({}, this.pathMapTo, { [oldKey]: newKey })
                    }
                }
            }
        },
        activeKey: function(newPathKey) {
            this.$router.push({ path: newPathKey })
        },
        fullPathList(val) {
            sessionStorage.setItem('tabFullPathList', JSON.stringify(val))
        },
        pages(val) {
            const list = val.map((item) => {
                return {
                    fullPath: item.fullPath,
                    path: item.path,
                    meta: item.meta
                }
            })
            sessionStorage.setItem('tabPages', JSON.stringify(list))
        },
        pathMap: {
            deep: true,
            handler(val) {
                sessionStorage.setItem('tabPathMap', JSON.stringify(val))
                this.$store.commit('tabInfo/SET_PATHMAP', val)
            }
        },
        pathMapTo: {
            deep: true,
            handler(val) {
                sessionStorage.setItem('tabPathMapTo', JSON.stringify(val))
            }
        }
    },
    computed: {
        currentKey: {
            get() {
                const result =
                    this.pathMap[this.activeKey] !== '/index' ? this.pathMap[this.activeKey] || this.activeKey : this.activeKey
                const { noTab } = this.$route.meta
                return noTab ? result : this.$route.fullPath
            },
            set(val) {
                this.activeKey = val
            }
        }
    },
    render() {
        const {
            onEdit,
            $data: { pages }
        } = this
        const pagesList = pages
        const panes = pagesList.map((page) => {
            return (
                <a-tab-pane
                    style={{ height: 0 }}
                    tab={this.renderTabPane(page.meta.customTitle || page.meta.title, page.fullPath)}
                    key={page.fullPath}
                    closable={pagesList.length > 1 && page.fullPath !== '/index'}
                ></a-tab-pane>
            )
        })
        return (
            <div class="ant-pro-multi-tab">
                <div class="ant-pro-multi-tab-wrapper">
                    <a-tabs
                        hideAdd
                        type={'editable-card'}
                        activeKey={this.currentKey}
                        onTabClick={this.resolvePathMapTo}
                        tabBarStyle={{ background: '#FFF', margin: 0, paddingLeft: '16px', paddingTop: '1px' }}
                        {...{ on: { edit: onEdit } }}
                    >
                        {panes}
                    </a-tabs>
                </div>
            </div>
        )
    }
}
</script>
